//
//  NMPOScanManager.swift
//  NMPO
//
//  Created by PowerfullClean on 2023/10/31.
//

import UIKit
import SwiftyJSON
import Alamofire

let nmpo_ipTokenUUID = "f1a6947fba8cd5"
extension NMPOManager {
    func nmpo_requestIPAddress(nmpo_complete:((String?)->())? = nil) {
        AF.request("http://ifconfig.me/ip", method: .get, parameters: nil){ nmpo_request in
            nmpo_request.timeoutInterval = 15
        }.responseString { nmpo_response in
            switch nmpo_response.result {
            case .failure(_):
                nmpo_complete?(nil)
                return
            case .success(_):
                break
            }
            guard let nmpo_ipString = nmpo_response.value else {
                nmpo_complete?(nil)
                return
            }
            print(nmpo_ipString)
            nmpo_complete?(nmpo_ipString)
        }
    }
    func nmpo_requestIPInfoModel()  {
        nmpo_requestIPAddress { nmpo_ipString in
            guard let nmpo_ipString = nmpo_ipString else {
                
                self.nmpo_delegate?.nmpo_iPScanFinish?(nmpo_model: nil)
                return
            }
            AF.request("http://ipinfo.io/\(nmpo_ipString)?token=\(nmpo_ipTokenUUID)", method: .get, parameters: nil){ nmpo_request in
                // 设置超时时间
                nmpo_request.timeoutInterval = 15
            }.responseString { nmpo_response in
                switch nmpo_response.result {
                case .failure(_):
                    
                    self.nmpo_delegate?.nmpo_iPScanFinish?(nmpo_model: nil)
                    return
                case .success(_):
                    break
                }
                guard let nmpo_ipInfoString = nmpo_response.value else {
                    self.nmpo_delegate?.nmpo_iPScanFinish?(nmpo_model: nil)
                    return
                }
                let nmpo_ipScanModel = NMPOIPScanModel(JSONString: nmpo_ipInfoString)
                self.nmpo_delegate?.nmpo_iPScanFinish?(nmpo_model: nmpo_ipScanModel)
                NotificationCenter.default.post(name: nmpo_funIPINFOUpdate_noti, object: nmpo_ipScanModel)
                self.nmpo_funcInModel = nmpo_ipScanModel
            }
        }
        
    }
}

let nmpo_saveDownloadFile = "nmpo_saveDownloadFile"
extension NMPOManager {
    func nmpo_stopDownloadTest() {
        if nmpo_downloadRequest == nil {
            return
            
        }
        nmpo_downloadRequest?.cancel()
        nmpo_downloadRequest = nil
    }
    func nmpo_stopUploadTest() {
        if nmpo_uploadRequest == nil {
            return
            
        }
        nmpo_uploadRequest?.cancel()
        nmpo_uploadRequest = nil
    }
    func nmpo_deleteLocalSaveVideo() {
        let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        let fileURL = documentsURL.appendingPathComponent("\(nmpo_saveDownloadFile).mp4")
        try? FileManager.default.removeItem(at: fileURL)
    }
    
    func nmpo_startSpeedScan() {
        
        nmpo_uploadValue = 0
        nmpo_downloadValue = 0
        NMPOSpeedValueVender.nmpo_toolManager().nmpo_startListening()
        NMPOSpeedValueVender.nmpo_toolManager().delegate = self
        nmpo_deleteLocalSaveVideo()
        nmpo_stopDownloadRequest = false
        nmpo_stopUploadRequest = false
        nmpo_startDownloadTestRequest()
    }
    func nmpo_stopSpeedScan() {
        nmpo_deleteLocalSaveVideo()
        nmpo_stopDownloadTest()
        nmpo_stopUploadTest()
        nmpo_stopUploadTestTimer()
        nmpo_stopDownloadTimerTest()
        nmpo_stopPingTest()
        self.nmpo_stopDownloadRequest = true
        self.nmpo_stopUploadRequest = true
        nmpo_delegate = nil
        nmpo_uploadValue = 0
        nmpo_downloadValue = 0
        NMPOSpeedValueVender.nmpo_toolManager().nmpo_stopListening()
        NMPOSpeedValueVender.nmpo_toolManager().delegate = nil
        nmpo_speedType = -1
    }
    private func nmpo_startDownloadTestRequest() {
        nmpo_speedType = 0
        nmpo_downAddDataTest()
        nmpo_startDownloadTimerTest()
        
    }
    private func nmpo_downAddDataTest() {
        if nmpo_stopDownloadRequest {
            return
        }
        let destination: DownloadRequest.Destination = { _, _ in
            let nmpo_documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
            let nmpo_fileURL = nmpo_documentsURL.appendingPathComponent("\(nmpo_saveDownloadFile).mp4")
            
            return (nmpo_fileURL, [.removePreviousFile, .createIntermediateDirectories])
        }
        nmpo_downloadRequest = AF.download("https://www.apple.com/105/media/cn/ipad/2018/08716702_0a2f_4b2c_9fdd_e08394ae72f1/films/browse-files/ipad-browse-files-tpl-cn-20180404_1280x720h.mp4", to: destination).responseString(completionHandler: { nmpo_res in
            if !self.nmpo_stopDownloadRequest {
                self.nmpo_downloadRequest?.cancel()
                self.nmpo_downloadRequest = nil
                if self.nmpo_downAddNumber > 5 {
                    self.nmpo_stopDownloadRequest = true
                    return
                }
                self.nmpo_downAddDataTest()
            }
            
        })
        
    }
    
    fileprivate func nmpo_startDownloadTimerTest() {
        nmpo_stopDownloadTimerTest()
        nmpo_downloadName = NMPOTimerVender.nmpo_timeTask(self, selector: #selector(nmpo_timerDownloadAdd), start: 0, interval: 1, repeats: true, async: false, name: nmpo_downloadName)
    }
    
    fileprivate func nmpo_stopDownloadTimerTest() {
        NMPOTimerVender.nmpo_cancelTask(nmpo_downloadName)
        nmpo_downloadName = "nmpo_downloadName"
        nmpo_downAddNumber = 0
    }
    
    @objc fileprivate func nmpo_timerDownloadAdd() {
        nmpo_downAddNumber = nmpo_downAddNumber + 1
        
        if nmpo_downAddNumber > 5 {
            self.nmpo_deleteLocalSaveVideo()
            self.nmpo_stopDownloadTimerTest()
            self.nmpo_homeDownloadValue = nmpo_downloadValue
            nmpo_delegate?.nmpo_downloadFinish?(nmpo_value: NMPOCommon.nmpo_changeSizeValue(size: nmpo_downloadValue))
            nmpo_stopDownloadTest()
            nmpo_startUploadTestRequest()
        }
    }
}

extension NMPOManager {
    fileprivate func nmpo_startUploadTestRequest() {
        nmpo_speedType = 1
        nmpo_deleteLocalSaveVideo()
        autoreleasepool {
            var nmpo_videoData = Data(repeating: 0x42, count: 50410840)
            let nmpo_videoData2 = nmpo_videoData
            nmpo_videoData.append(nmpo_videoData2)
            nmpo_sumUpVideoData(nmpo_data: nmpo_videoData)
            nmpo_startUpTimerTest()
        }
        
    }
    fileprivate func nmpo_sumUpVideoData(nmpo_data: Data, nmpo_isAdd: Bool = true) {
        if nmpo_stopUploadRequest {
            return
        }
        var nmpo_videoData = nmpo_data
        if nmpo_isAdd {
            nmpo_videoData.append(nmpo_data)
        }
        
        nmpo_uploadRequest = AF.upload(multipartFormData: { multipartFormData in
            multipartFormData.append(nmpo_videoData, withName: "file")
        }, to: "https://httpbin.org/post")
        
        nmpo_uploadRequest?.responseString(completionHandler: { nmpo_res in
            if !self.nmpo_stopUploadRequest {
                self.nmpo_uploadRequest?.cancel()
                self.nmpo_uploadRequest = nil
                if self.nmpo_uploadAddNumber > 5 {
                    self.nmpo_stopUploadRequest = true
                    return
                }
                
                self.nmpo_sumUpVideoData(nmpo_data: nmpo_videoData, nmpo_isAdd: false)
            }
            
        })
        
        
    }
    fileprivate func nmpo_startUpTimerTest() {
        nmpo_stopUploadTestTimer()
        nmpo_uploadName = NMPOTimerVender.nmpo_timeTask(self, selector: #selector(nmpo_timerUploadAdd), start: 0, interval: 1, repeats: true, async: false, name: nmpo_uploadName)
    }
    
    fileprivate func nmpo_stopUploadTestTimer() {
        NMPOTimerVender.nmpo_cancelTask(nmpo_uploadName)
        nmpo_uploadName = "nmpo_uploadName"
        nmpo_uploadAddNumber = 0
    }
    
    @objc fileprivate func nmpo_timerUploadAdd() {
        nmpo_uploadAddNumber = nmpo_uploadAddNumber + 1
        
        if nmpo_uploadAddNumber > 5 {
            nmpo_stopUploadTestTimer()
            self.nmpo_homeUploadValue = nmpo_uploadValue
            self.nmpo_delegate?.nmpo_upLoadFinish?(nmpo_value: NMPOCommon.nmpo_changeSizeValue(size: nmpo_uploadValue))
            nmpo_stopUploadTest()
            self.nmpo_startSpeedScanPing()
        }
    }
}

extension NMPOManager {
    func nmpo_startSpeedScanPing() {
        nmpo_speedType = 2
        if nmpo_vpnCurStateType == .nmpo_connected {
            self.nmpo_delegate?.nmpo_pingFinish?(nmpo_ping: "0ms", nmpo_jitter: "0ms", nmpo_loss: "0%")
            return
        }
        var nmpo_values = [Int]()
        nmpo_pingobjct = try? NMPOSwiftyPingVender(host: "www.apple.com", configuration: PingConfiguration(interval: 0.5, with: 1), queue: DispatchQueue.global())
        nmpo_pingobjct?.observer = { (response) in
            if response.error != nil {
                self.nmpo_delegate?.nmpo_pingFinish?(nmpo_ping: "0ms", nmpo_jitter: "0ms", nmpo_loss: "0%")
                self.nmpo_stopPingTest()
                return
            }
            let duration = response.duration
            print(response)
            let nmpo_pingValue = NSInteger(duration*1000)
            nmpo_values.append(nmpo_pingValue)
            let nmpo_allCount:Double = Double(nmpo_values.count)
            if nmpo_values.count >= 5 {
                nmpo_values = nmpo_values.filter({ nmpo_va in
                    return nmpo_va != 0
                })
                let nmpo_value = nmpo_values.reduce(0)  {
                    $0 + $1
                }
                if nmpo_value == 0 || nmpo_values.count == 0 {
                    self.nmpo_stopPingTest()
                    self.nmpo_delegate?.nmpo_pingFinish?(nmpo_ping: "0ms", nmpo_jitter: "0ms", nmpo_loss: "0%")
                    return
                }
               
                let nmpo_lossC:Double = nmpo_allCount-Double(nmpo_values.count)
                let nmpo_loss = Int((nmpo_lossC/nmpo_allCount)*100)
                let nmpo_jitter = (nmpo_values.max() ?? 0) - (nmpo_values.min() ?? 0)
                self.nmpo_delegate?.nmpo_pingFinish?(nmpo_ping: "\(nmpo_value/nmpo_values.count)ms", nmpo_jitter: "\(nmpo_jitter)ms", nmpo_loss: "\(nmpo_loss)%")
            }
            
        }
        nmpo_pingobjct?.targetCount = 5
        try? nmpo_pingobjct?.startPinging()
       
    }
    func nmpo_stopPingTest() {
        nmpo_pingobjct?.stopPinging()
        nmpo_pingobjct = nil
    }
    @objc func nmpo_pingVPNIPAddressAction(nmpo_vpnReqModel: NMPOVPNRequestModel, nmpo_group: DispatchGroup, nmpo_queue: DispatchQueue, nmpo_complete:(()->())? = nil) {
        if self.nmpo_vpnCurStateType == .nmpo_connected {
            nmpo_complete?()
            return
        }
        print("开始ping 节点==========================================")
        for nmpo_reqModel in nmpo_vpnReqModel.nmpo_crkZQ.nmpo_qlHTP {
            nmpo_group.enter() // 进入 Dispatch Group
            nmpo_queue.async {
                
                let pinger = try? NMPOSwiftyPingVender(host: nmpo_reqModel.nmpo_bTuIq, configuration: PingConfiguration(interval: 0.5, with: 5), queue: nmpo_queue)
                pinger?.observer = { (response) in
                    let duration = response.duration
                    nmpo_reqModel.nmpo_pingValue = NSInteger(duration*1000)
                    print("\(nmpo_reqModel.nmpo_bTuIq) 节点ping结束==========================================\(NSInteger(duration*1000))")
                    nmpo_group.leave()
                }
                pinger?.targetCount = 1
                try? pinger?.startPinging()
                
            }
        }
        nmpo_group.notify(queue: .main) {
            print("All pings are complete")
            nmpo_complete?()
        }
        
    }
}

extension NMPOManager: NMPOSpeedValueToolDelegate {
    func nmpo_updateNetSendValue(_ nmpo_value: UInt64) {
        if nmpo_speedType != 1 {
            return
        }
        nmpo_uploadValue += Double(nmpo_value)
        print(nmpo_uploadValue, "上传")
    }
    func nmpo_updateNetReceiveValue(_ nmpo_value: UInt64) {
        if nmpo_speedType != 0 {
            return
        }
        nmpo_downloadValue += Double(nmpo_value)
        print(nmpo_downloadValue, "下载", nmpo_value)
    }
}
